//---------------------------------------------------------------------------
// Name:	SimpleRequest.cpp
// Desc:	Source of CSimpleRequest
// Author:	D.C
// Date:	2007-09-04
//---------------------------------------------------------------------------
#include <utf.h>
#include <EscapeUtils.h>
#include "simplerequest.h"
#include "utils.h"

#include "elog.h"

#define TimerDelay (100000)//100ms
_LIT8(HDR_RESPONSE_CODE, "HTTP/1.");
_LIT8(SPACE8, " ");
_LIT8(LINE_END, "\r\n");
_LIT8(TYPE_FIX, ";");
_LIT8(HDR_FILE_TYPE, "Content-Type:");
_LIT8(VND_WAP_XML,"text/vnd.wap.wml");
_LIT8(DATA_START,"\r\n\r\n");
_LIT8(HDR_GETREQUEST,"GET %S HTTP/1.0\r\nHost: %S:%d\r\nAccept: */*\r\nUser-Agent: modove/1.0\r\nConnection: Close\r\n\r\n");
_LIT8(HDR_POSTREQUEST,"POST %S HTTP/1.0\r\nHost: %S:%d\r\nAccept: */*\r\nUser-Agent: modove/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-length: %d\r\nConnection: Close\r\n\r\n%S\r\n\r\n");

CSimpleRequest* CSimpleRequest::NewL()
{
	CSimpleRequest* self=new (ELeave) CSimpleRequest();
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
}

CSimpleRequest::~CSimpleRequest()
{
	Disconnect();
	SAFE_DELETE( m_pTimer );
	SAFE_DELETE( m_pMeteor );
}

CSimpleRequest::CSimpleRequest()
{
	m_pMeteor=NULL;
	m_pObserver=NULL;
	m_pTimer=NULL;
	m_pHost=NULL;
	m_pLRL=NULL;
	m_pHeapBuf=NULL;
	m_pFileType=NULL;
	m_pURL=NULL;
	m_iResponseCode=m_iPort=0;
	iRequestType=REQUEST_NONE;
	m_eFlag=TDF_NotConnected;
	iPostString=0;
}

void CSimpleRequest::ConstructL()
{
	m_pTimer=CTimeOutTimer::NewL(this);
	m_pMeteor=CMeteor::NewL(this);
}

void CSimpleRequest::SetObserver(MSimpleRequestObserver* aObserver)
{
	m_pObserver=aObserver;
}

TInt CSimpleRequest::Connect(const TDesC& aHost,TInt aPort,TUint32 aIAP)
{
	LOOG(_L("CSimpleRequest::Connect"));
	m_iIAP=aIAP;
	SAFE_DELETE(m_pHost);
	m_pHost=HBufC8::New(aHost.Length()*2);
	TPtr8 ptrHost(m_pHost->Des());
	ptrHost.Copy(aHost);
	m_iPort=aPort;
	iRequestType=REQUEST_CONNECT;
	m_eFlag=TDF_NotConnected;
	m_pTimer->After(TimerDelay);
	return KErrNone;
}

void CSimpleRequest::Disconnect()
{
	LOOG(_L("CSimpleRequest::Disconnect"));
	Reset();
	m_pMeteor->Disconnect();
	SAFE_DELETE( m_pHost );
	SAFE_DELETE( m_pLRL );
	SAFE_DELETE( m_pURL );
	SAFE_DELETE( m_pFileType );
	SAFE_DELETE(iPostString);
	m_iPort=0;
	iRequestType=REQUEST_NONE;
	m_eFlag=TDF_NotConnected;
}
void CSimpleRequest::Reset()
{
	LOOG(_L("CSimpleRequest::Reset"));
	SAFE_DELETE(m_pHeapBuf);
	m_pTimer->Cancel();
	m_pMeteor->CloseSocket();
	m_eFlag=TDF_Connected;
	m_iResponseCode=0;
}
TInt CSimpleRequest::Get(const TDesC& aRequest)
{
	LOOG(_L("CSimpleRequest::Get"));
	HBufC8* aURL=HBufC8::New(aRequest.Length()*2);
	TPtr8 ptr(aURL->Des());
	CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr,aRequest);
	SAFE_DELETE(m_pURL);
	m_pURL=EscapeUtils::EscapeEncodeL(ptr,EscapeUtils::EEscapeNormal);
	SAFE_DELETE(aURL);
	
	_LIT8(PORT_LABLE, ":");
	_LIT8(HOST_END, "/");
	HBufC8* aPort=NULL;
	TInt aPos=m_pURL->Mid(7).Find(HOST_END);
	TInt aPos2=m_pURL->Mid(7).Find(PORT_LABLE);
	if (KErrNotFound==aPos)
	{
		return KErrNotFound;
	}
	if (KErrNotFound!=aPos2&&aPos2<aPos)
	{
		aPort=m_pURL->Mid(7).Mid(aPos2+1,aPos-aPos2-1).Alloc();
		TLex8 lex(aPort->Des());
		lex.Val(m_iPort);
		SAFE_DELETE(aPort);
		SAFE_DELETE(m_pHost);
		SAFE_DELETE(m_pLRL);
		m_pHost=m_pURL->Mid(7).Mid(0,aPos2).Alloc();
		m_pLRL=m_pURL->Mid(7).Mid(aPos).Alloc();
	}
	else
	{
		m_iPort=80;
		if (KErrNotFound==aPos)
		{
			return KErrNotFound;
		}
		else
		{
			SAFE_DELETE(m_pHost);
			SAFE_DELETE(m_pLRL);
			m_pHost=m_pURL->Mid(7).Mid(0,aPos).Alloc();
			m_pLRL=m_pURL->Mid(7).Mid(aPos).Alloc();
		}
	}

	iRequestType=REQUEST_GET;
	m_eFlag=TDF_Connected;
	m_pTimer->After(TimerDelay);
	return KErrNone;
}

TInt CSimpleRequest::Post(const TDesC& aRequest,const TDesC& aRequest2)
{
	LOOG(_L("CSimpleRequest::Post"));
	HBufC8* aURL=HBufC8::New(aRequest.Length()*2);
	TPtr8 ptr(aURL->Des());
	CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr,aRequest);
	SAFE_DELETE(m_pURL);
	m_pURL=EscapeUtils::EscapeEncodeL(ptr,EscapeUtils::EEscapeNormal);
	SAFE_DELETE(aURL);
	
	_LIT8(PORT_LABLE, ":");
	_LIT8(HOST_END, "/");
	HBufC8* aPort=NULL;
	TInt aPos=m_pURL->Mid(7).Find(HOST_END);
	TInt aPos2=m_pURL->Mid(7).Find(PORT_LABLE);
	if (KErrNotFound==aPos)
	{
		return KErrNotFound;
	}
	if (KErrNotFound!=aPos2&&aPos2<aPos)
	{
		aPort=m_pURL->Mid(7).Mid(aPos2+1,aPos-aPos2-1).Alloc();
		TLex8 lex(aPort->Des());
		lex.Val(m_iPort);
		SAFE_DELETE(aPort);
		SAFE_DELETE(m_pHost);
		SAFE_DELETE(m_pLRL);
		m_pHost=m_pURL->Mid(7).Mid(0,aPos2).Alloc();
		m_pLRL=m_pURL->Mid(7).Mid(aPos).Alloc();
	}
	else
	{
		m_iPort=80;
		if (KErrNotFound==aPos)
		{
			return KErrNotFound;
		}
		else
		{
			SAFE_DELETE(m_pHost);
			SAFE_DELETE(m_pLRL);
			m_pHost=m_pURL->Mid(7).Mid(0,aPos).Alloc();
			m_pLRL=m_pURL->Mid(7).Mid(aPos).Alloc();
		}
	}

	HBufC8* aPostString=HBufC8::New(aRequest2.Length()*2);
	TPtr8 ptr2(aPostString->Des());
	CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr2,aRequest2);
	SAFE_DELETE(iPostString);
	iPostString=EscapeUtils::EscapeEncodeL(ptr2,EscapeUtils::EEscapeNormal);
	SAFE_DELETE(aPostString);
	iRequestType=REQUEST_POST;
	m_eFlag=TDF_Connected;
	m_pTimer->After(TimerDelay);
	return KErrNone;
}

TInt CSimpleRequest::ParseResponseCode()
{
	if (NULL==m_pHeapBuf)
		return KErrBadDescriptor;
	TInt pos=m_pHeapBuf->Find(HDR_RESPONSE_CODE);
	if (KErrNotFound==pos)
	{
		return KErrNotFound;
	}
	else
	{
		pos+=HDR_RESPONSE_CODE().Length()+2; //"HTTP/1.x "
		TInt pos2=m_pHeapBuf->Mid(pos).Find(SPACE8);
		if (KErrNotFound==pos2)
			return KErrNotFound;
		TLex8 lex(m_pHeapBuf->Mid(pos,pos2));
		lex.Val(m_iResponseCode);
	}
	return KErrNone;
}

TInt CSimpleRequest::ParseFileType()
{
	if (NULL==m_pHeapBuf)
		return KErrBadDescriptor;
	TInt pos=m_pHeapBuf->Find(HDR_FILE_TYPE);
	if (KErrNotFound==pos)
	{
		return KErrNotFound;
	}
	else
	{
		pos+=HDR_FILE_TYPE().Length()+1; //"Content-Type: "
		TInt pos2=m_pHeapBuf->Mid(pos).Find(LINE_END);
		TInt pos3=m_pHeapBuf->Mid(pos).Find(TYPE_FIX);
		if (KErrNotFound==pos2)
		{
			return KErrNotFound;
		}
		if (KErrNotFound!=pos3&&pos3<pos2)
		{
			pos2=pos3;
		}
		HBufC8* p=m_pHeapBuf->Mid(pos,pos2).Alloc();
		SAFE_DELETE( m_pFileType );
		m_pFileType=p;
	}
	return KErrNone;
}

void CSimpleRequest::Request()
{
	if (NULL==m_pMeteor||NULL==m_pURL||NULL==m_pLRL||NULL==m_pHost)
	{
		Reset();
		if (NULL!=m_pObserver)
		{
			m_pObserver->SimpleRequestError(KErrAccessDenied);
		}
	}
	TInt i=0;
	if (m_pMeteor->ProxyUsed())
	{
		if(REQUEST_GET==iRequestType)
		{
			i=HDR_GETREQUEST().Length()+m_pURL->Length()+m_pHost->Length()+GetNumLen(m_iPort);
		}
		else if(REQUEST_POST==iRequestType)
		{
			TInt post_len=iPostString->Length();
			i=HDR_POSTREQUEST().Length()+m_pURL->Length()+m_pHost->Length()+GetNumLen(m_iPort)+GetNumLen(post_len)+post_len;			
		}
	}
	else
	{
		if(REQUEST_GET==iRequestType)
		{
			i=HDR_GETREQUEST().Length()+m_pLRL->Length()+m_pHost->Length()+GetNumLen(m_iPort);
		}
		else if(REQUEST_POST==iRequestType)
		{
			TInt post_len=iPostString->Length();
			i=HDR_POSTREQUEST().Length()+m_pLRL->Length()+m_pHost->Length()+GetNumLen(m_iPort)+GetNumLen(post_len)+post_len;
		}
	}

	HBufC8* hdr=HBufC8::New(i);
	TPtr8 ptr(hdr->Des());
	if (m_pMeteor->ProxyUsed())
	{
		if(REQUEST_GET==iRequestType)
		{
			ptr.AppendFormat(HDR_GETREQUEST,m_pURL,m_pHost,m_iPort);
		}
		else if(REQUEST_POST==iRequestType)
		{
			TInt post_len=iPostString->Length();
			ptr.AppendFormat(HDR_POSTREQUEST,m_pURL,m_pHost,m_iPort,post_len,iPostString);
		}
	}
	else
	{
		if(REQUEST_GET==iRequestType)
		{
			ptr.AppendFormat(HDR_GETREQUEST,m_pLRL,m_pHost,m_iPort);
		}
		else if(REQUEST_POST==iRequestType)
		{
			TInt post_len=iPostString->Length();
			ptr.AppendFormat(HDR_POSTREQUEST,m_pLRL,m_pHost,m_iPort,post_len,iPostString);
		}
	}

	TInt iRet=m_pMeteor->Write(hdr->Des());

	SAFE_DELETE( hdr );
	if (KErrNone!=iRet)
	{
		m_eFlag=TDF_NotConnected;
		if (NULL!=m_pObserver)
		{
			m_pObserver->SimpleRequestError(KErrAbort);
		}
	}
}

void CSimpleRequest::TimerExpired()
{
	LOOG(_L("CSimpleRequest::TimerExpired:%d"),m_eFlag);
	m_pTimer->Cancel();
	switch(m_eFlag)
	{
		case TDF_NotConnected:
		{
			HBufC* aHost=HBufC::New(m_pHost->Length());
			TPtr aHostPtr(aHost->Des());
			aHostPtr.Copy(m_pHost->Des());
			TInt err=m_pMeteor->Connect(aHostPtr,m_iPort,m_iIAP);
			if (KErrNone!=err)
			{
				m_eFlag=TDF_NotConnected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
			}
			SAFE_DELETE(aHost);
		}
		break;
		case TDF_Connected:
		case TDF_DNSReady:
		{
			if(REQUEST_CONNECT==iRequestType)
			{
				m_pObserver->ConnectComplete(KErrNone);
			}
			else
			{
				m_pMeteor->CloseSocket();
				if (KErrNone!=m_pMeteor->OpenSocket())
				{
					m_eFlag=TDF_Connected;
					if (NULL!=m_pObserver)
					{
						m_pObserver->SimpleRequestError(KErrAbort);
					}
				}
			}
		}
		break;
		case TDF_SocketOpened:
		{
			Request();
		}
		break;
		case TDF_DataWriteOver:
		{
			if (KErrNone!=m_pMeteor->Read())
			{
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
			}
		}
		break;
		case TDF_DataReading:
		{
			//read again
			if (KErrNone!=m_pMeteor->Read())
			{
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
			}
		}
		break;
		case TDF_DataReadOver:
		{
			//1.ParseResponseCode
			if (NULL==m_pHeapBuf)
			{
				//error
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
				break;
			}
			TInt ret=ParseResponseCode();
			TInt http_code=m_iResponseCode;
			if (KErrNone!=ret)
			{
				//error                
				SAFE_DELETE( m_pHeapBuf );
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
				break;
			}
			if (http_code!=200)
			{
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
				break;
			}
			//2.ParseFileType
			ret=ParseFileType();
			if (KErrNone!=ret||NULL==m_pFileType)
			{
				//error
				SAFE_DELETE( m_pHeapBuf );
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
				break;
			}
			if (0==m_pFileType->Compare(VND_WAP_XML))
			{
				//again
				SAFE_DELETE( m_pHeapBuf );
				m_eFlag=TDF_Connected;
				m_pTimer->After(TimerDelay);
				break;
			}
			//3.extract data
			TInt pos=m_pHeapBuf->Find(DATA_START);
			if (KErrNotFound==pos)
			{
				//error
				SAFE_DELETE( m_pHeapBuf );
				m_eFlag=TDF_Connected;
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestError(KErrAbort);
				}
				break;
			}
			else
			{
				pos+=DATA_START().Length();
				HBufC8* p=m_pHeapBuf->Mid(pos).Alloc();
				//over                    
				if (NULL!=m_pObserver)
				{
					m_pObserver->SimpleRequestFinish(*p);
				}
				SAFE_DELETE(p);
			}
		}
		break;
		default:
		{
			if (NULL!=m_pObserver)
			{
				m_pObserver->SimpleRequestError(KErrUnknown);
			}
		}
		break;
	}
}
void CSimpleRequest::ConnectionComplete(TInt aCode)
{
	LOOG(_L("CSimpleRequest::ConnectionComplete(%d)"),aCode);
	m_pTimer->Cancel();
	switch(aCode)
	{
		case KErrNone:
		{
			m_eFlag=TDF_Connected;
			m_pTimer->After(TimerDelay);
		}
		break;
		default:
		{
			if (NULL!=m_pObserver)
			{
				if(REQUEST_CONNECT==iRequestType)
				{
					m_pObserver->ConnectComplete(aCode);
				}
				else
				{
					m_pObserver->SimpleRequestError(aCode);
				}
			}
		}
		break;
	}
}
void CSimpleRequest::DNSComplete(TInt aCode)
{
	LOOG(_L("CSimpleRequest::DNSComplete(%d)"),aCode);
	m_pTimer->Cancel();
	switch(aCode)
	{
		case KErrNone:
		{
			m_eFlag=TDF_DNSReady;
			m_pTimer->After(TimerDelay);
		}
		break;
		default:
		{
			if (NULL!=m_pObserver)
			{
				m_pObserver->SimpleRequestError(aCode);
			}
		}
		break;
	}
}
void CSimpleRequest::SocketOpenComplete(TInt aCode)
{
	LOOG(_L("CSimpleRequest::SocketOpenComplete(%d)"),aCode);
	m_pTimer->Cancel();
	switch(aCode)
	{
		case KErrNone:
		{
			m_eFlag=TDF_SocketOpened;
			m_pTimer->After(TimerDelay);
		}
		break;
		default:
		{
			if (NULL!=m_pObserver)
			{
				m_pObserver->SimpleRequestError(aCode);
			}
		}
		break;
	}
}
void CSimpleRequest::WriteBufferComplete(TInt aCode)
{
	LOOG(_L("CSimpleRequest::WriteBufferComplete(%d)"),aCode);
	m_pTimer->Cancel();
	switch(aCode)
	{
		case KErrNone:
		{
			m_eFlag=TDF_DataWriteOver;
			m_pTimer->After(TimerDelay);
		}
		break;
		default:
		{
			if (NULL!=m_pObserver)
			{
				m_pObserver->SimpleRequestError(aCode);
			}
		}
		break;
	}
}
void CSimpleRequest::ReadBufferComplete(TInt aCode,const TDesC8& aBuf)
{
	LOOG(_L("CSimpleRequest::ReadBufferComplete(%d)"),aCode);
	LOOG(aBuf);
	m_pTimer->Cancel();
	switch(aCode)
	{
		case KErrNone:
		case KErrEof:
		case KErrDisconnected:
		case KErrTimedOut:
		{
			if (NULL==m_pHeapBuf)
			{
				m_pHeapBuf=aBuf.Alloc();
			}
			else
			{
				TInt i=m_pHeapBuf->Length()+aBuf.Length();
				HBufC8* tmp=HBufC8::New(i);
				TPtr8 ptr(tmp->Des());
				ptr.Copy(*m_pHeapBuf);
				ptr.Append(aBuf);
				SAFE_DELETE(m_pHeapBuf);
				m_pHeapBuf=tmp;
			}
			m_eFlag=((KErrNone==aCode)?(TDF_DataReading):(TDF_DataReadOver));
			if (NULL!=m_pObserver)
			{
				m_pObserver->SimpleRequestPos(aBuf.Length());
			}
			m_pTimer->After(TimerDelay);
		}
		break;
		default:
		{
			if (NULL!=m_pObserver)
			{
				m_pObserver->SimpleRequestError(aCode);
			}
		}
		break;
	}
}
void CSimpleRequest::UnknowComplete(TInt aCode)
{
	LOOG(_L("CSimpleRequest::UnknowComplete(%d)"),aCode);
	m_pTimer->Cancel();
	if (NULL!=m_pObserver)
	{
		m_pObserver->SimpleRequestError(aCode);
	}
}
